package com.lighting.common.core.util;

import com.lighting.common.core.vo.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.util.*;

/**
 * 对象转换工具类
 */
@Slf4j
public class ObjectUtil {

    /**
     * 转换为Long类型
     */
    public static Long convertToLong(Object value) {
        if (value == null) return null;
        if (value instanceof Number) {
            return ((Number) value).longValue();
        }
        return Long.parseLong(value.toString());
    }

    /**
     * 转换为Double类型
     */
    public static Double convertToDouble(Object value) {
        if (value == null) return null;
        if (value instanceof Number) {
            return ((Number) value).doubleValue();
        }
        return Double.parseDouble(value.toString());
    }

    /**
     * 转换为String类型
     */
    public static String convertToString(Object value) {
        return value != null ? value.toString() : null;
    }

    /**
     * 转换为Date类型
     */
    public static Date convertToDate(Object value) {
        if (value == null) return null;
        if (value instanceof Timestamp) {
            return new Date(((Timestamp) value).getTime());
        }
        if (value instanceof Date) {
            return (Date) value;
        }
        return null;
    }

    /**
     * 转换为Boolean类型
     */
    public static Boolean convertToBoolean(Object value) {
        if (value == null) return null;
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        return Boolean.parseBoolean(value.toString());
    }


    /**
     * 拷贝对象属性（忽略null值）
     *
     * @param source 源对象
     * @param target 目标对象
     */
    public static void copyPropertiesIgnoreNull(Object source, Object target) {
        copyProperties(source, target, true);
    }

    /**
     * 拷贝对象属性（忽略null值和指定属性）
     *
     * @param source           源对象
     * @param target           目标对象
     * @param ignoreProperties 要忽略的属性名
     */
    public static void copyProperties(Object source, Object target, String... ignoreProperties) {
        copyProperties(source, target, true, ignoreProperties);
    }

    /**
     * 拷贝对象属性
     *
     * @param source     源对象
     * @param target     目标对象
     * @param ignoreNull 是否忽略null值
     */
    public static void copyProperties(Object source, Object target, boolean ignoreNull) {
        copyProperties(source, target, ignoreNull, new String[0]);
    }

    /**
     * 拷贝对象属性
     *
     * @param source           源对象
     * @param target           目标对象
     * @param ignoreNull       是否忽略null值
     * @param ignoreProperties 要忽略的属性名
     */
    public static void copyProperties(Object source, Object target, boolean ignoreNull, String... ignoreProperties) {
        if (source == null) {
            return;
        }
        Assert.notNull(target, "Target must not be null");

        Set<String> ignoreSet = new HashSet<>(Arrays.asList(ignoreProperties));
        Class<?> sourceClass = source.getClass();
        Class<?> targetClass = target.getClass();

        List<Field> sourceFields = getAllFields(sourceClass);
        List<Field> targetFields = getAllFields(targetClass);

        for (Field sourceField : sourceFields) {
            try {
                String fieldName = sourceField.getName();
                // 如果字段在忽略列表中，则跳过
                if (ignoreSet.contains(fieldName)) {
                    continue;
                }

                sourceField.setAccessible(true);
                Object value = sourceField.get(source);

                // 如果忽略null且值为null，则跳过
                if (ignoreNull && value == null) {
                    continue;
                }

                // 查找目标类中同名字段
                for (Field targetField : targetFields) {
                    if (targetField.getName().equals(fieldName)) {
                        targetField.setAccessible(true);
                        // 处理基本类型和包装类型的兼容性
                        if (isCompatibleType(sourceField.getType(), targetField.getType())) {
                            targetField.set(target, value);
                        }
                        break;
                    }
                }
            } catch (IllegalAccessException e) {
                // 忽略无法访问的字段
            }
        }
    }

    /**
     * 获取类及其父类的所有字段
     */
    private static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
        Class<?> superClass = clazz.getSuperclass();
        if (superClass != null) {
            fields.addAll(new ArrayList<>(getAllFields(superClass)));
        }
        return fields;
    }

    /**
     * 检查类型是否兼容
     */
    private static boolean isCompatibleType(Class<?> sourceType, Class<?> targetType) {
        // 相同类型
        if (sourceType.equals(targetType)) {
            return true;
        }
        // 基本类型和包装类型的兼容
        if (sourceType.isPrimitive()) {
            return getWrapperType(sourceType).equals(targetType);
        }
        if (targetType.isPrimitive()) {
            return getWrapperType(targetType).equals(sourceType);
        }
        // 子类可以赋值给父类
        return targetType.isAssignableFrom(sourceType);
    }

    /**
     * 获取基本类型的包装类型
     */
    private static Class<?> getWrapperType(Class<?> primitiveType) {
        if (primitiveType == int.class) return Integer.class;
        if (primitiveType == long.class) return Long.class;
        if (primitiveType == double.class) return Double.class;
        if (primitiveType == float.class) return Float.class;
        if (primitiveType == boolean.class) return Boolean.class;
        if (primitiveType == char.class) return Character.class;
        if (primitiveType == byte.class) return Byte.class;
        if (primitiveType == short.class) return Short.class;
        return primitiveType;
    }

    public static <D> D copy(Object o, Class<D> dClass) {
        if (o == null) {
            return null;
        }
        D dto;
        try {
            dto = dClass.newInstance();
        } catch (Exception e) {
            throw new BusinessException("创建DTO失败", e);
        }
        BeanUtils.copyProperties(o, dto);
        return dto;
    }

    public static Integer convertToInteger(Object o) {
        if (o == null) {
            return null;
        }
        if (o instanceof Integer) {
            return (Integer) o;
        }
        if (o instanceof Number) {
            return ((Number) o).intValue();
        }
        return Integer.parseInt(o.toString());
    }
}
